/*
 * eeprom.c
 *
 *  Created on: 2012-6-8
 *      Author: Administrator
 */

#include "tangoc.h"


void input_read_eeprom(unsigned short int *addr, int *bytes)
{
	label_addr: printf("Input address: ");
	scanf("%d", addr);
	getchar();
	if (*addr < 0 || *addr > 12287)
	{
		puts("Invalid address.");
		goto label_addr;
	}

	label_num: printf("Read bytes number: ");
	scanf("%d", bytes);
	getchar();
	if (*bytes <= 0 || *bytes + *addr > 12288)
	{
		puts("Invalid number.");
		goto label_num;
	}
}

void save_data(char *fname, char *buf, int len)
{
	int fptr;
	fptr = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	if (fptr == -1)
	{
		puts("Open file failed.");
		return;
	}
	write(fptr, buf, len);
	close(fptr);
}

int read_eeprom()
{
	int i, ret, bytes = 16;
	int total, len = 0;
	unsigned char cmd[4];
	unsigned char *p, *q;
	unsigned short int num;
	union short_char addr;

	input_read_eeprom(&num, &bytes);
	total = 3 * bytes + bytes / 16 + 1;
	p = (unsigned char *) malloc(bytes * sizeof(char));
	q = (unsigned char *) malloc(total);
	if (!p || !q)
	{
		puts("Not enough memory.");
		return 0;
	}
	memset(p, 0, bytes);
	memset(q, 0, total);
	strcpy(q, "\0");

	ioctl(gdev, DISABLE_IRQ, 0);
	ioctl(gdev, DEFAULT, 0);
	cmd[0] = 58;
	cmd[1] = 1;
	addr.num = (unsigned short int) num;
	cmd[2] = addr.buf[0];
	cmd[3] = addr.buf[1];
	write(gdev, cmd, 4);
	msleep(100);

	ret = read(gdev, p, bytes);
	if (ret == -1)
	{
		puts("read data failed.");
		return 0;
	}
	ioctl(gdev, ENABLE_IRQ, 0);

	printf("hex data:\n");
	for (i = 0; i < bytes; i++)
	{
		char tmp[16] = "\0";
		if (i % 16 == 0 && i > 0)
		{
			if (p[i] < 16) sprintf(tmp, "\n0%x ", p[i]);
			else sprintf(tmp, "\n%x ", p[i]);
		}
		else
		{
			if (p[i] < 16) sprintf(tmp, "0%x ", p[i]);
			else sprintf(tmp, "%x ", p[i]);
		}
		printf("%s", tmp);
		strcat(q, tmp);
		len += strlen(tmp);
	}
	printf("\n");
	save_data("eeprom.txt", q, len);
	free(p);
	free(q);

	return ret;
}

int write_eeprom()
{
	int ret, dat, num;
	union short_char addr;

	ioctl(gdev, WEEPROM, 0);
	printf("Input address: ");
	scanf("%d", &num);
	while (getchar() != '\n');
	printf("write one byte: ");
	scanf("%d", &dat);
	while (getchar() != '\n');

	addr.num = (short int) num;
	ret = write(gdev, addr.buf, sizeof(short int));
	if (ret == -1)
	{
		puts("write address failed.");
		return 0;
	}

	unsigned char byte = (unsigned char) dat;
	ret = write(gdev, &byte, 1);
	if (ret == -1)
	{
		puts("write data failed.");
		return 0;
	}
	else
	{
		puts("write data successfully.");
		return 1;
	}
}

int eeprom_offset()
{
	const int N = 1024 * 6;
	const int M = 384 * (5 * 16 + 2);
	char cmd[4], buf[16];
	int i, j;
	union short_char addr;
	char *p = (char *) malloc(M);

	if (p == NULL)
	{
		puts("Not enough memory.");
		return 0;
	}
	ioctl(gdev, DISABLE_IRQ, 0);
	ioctl(gdev, DEFAULT, 0);
	cmd[0] = 58;
	cmd[1] = 1;
	memset(p, 0, M);
	for (j = 0; j < N / 16; j++)
	{
		char str[256];
		addr.num = 1024 + j * 16;
		cmd[2] = addr.buf[0];
		cmd[3] = addr.buf[1];
		if (write(gdev, cmd, 4) != 4)
		{
			puts("Write failed.");
			break;
		}
		if (read(gdev, buf, 16) != 16)
		{
			puts("Read failed.");
			break;
		}
		strcpy(str, "\0");
		for (i = 0; i < 16; i++)
		{
			char tmp[16] = "";
			if (buf[i] < 16)
			{
				sprintf(tmp, "0x0%x", buf[i]);
			}
			else
			{
				sprintf(tmp, "0x%x", buf[i]);
			}
			if (j * 16 + i < N - 1) strcat(tmp, ",");
			strcat(str, tmp);
		}
		(j < N / 16 - 1) ? strcat(str, "\\\n") : strcat(str, "\n");
		strcat(p, str);
		printf("%s", str);
	}
	printf("\n");
	ioctl(gdev, ENABLE_IRQ, 0);
	save_data("offset.txt", p, strlen(p));
	free(p);

	return 0;
}

void eeprom_menu()
{
	puts("\nEEPROM menu, press a key in brackes.");
	puts("[R] Read EEPROM");
	//puts("[W] Write EEPROM");
	puts("[O] EEPROM offset");
	puts("[B] Back main menu");
	puts("[X] Exit");
}

void EEPROM_mode()
{
	char cmd, flag = 'n';
	int type = 1;
	unsigned char loop = 1;

	eeprom_menu();
	while (loop)
	{
		printf("Input cmd: ");
		cmd = getchar();
		while (getchar() != '\n')
			;
		switch (cmd)
		{
		case 'r':
		case 'R':
			read_eeprom();
			break;
//		case 'w':
//		case 'W':
//			break;
		case 'o':
		case 'O':
			eeprom_offset();
			break;
		case 'b':
		case 'B':
			loop = 0;
			main_menu();
			break;
		case 'x':
		case 'X':
			finish();
			break;
		}
		eeprom_menu();
	}
}

